winsafe\kernel\utilities/
w_string.rs1use std::cmp::Ordering;
2
3use crate::co;
4use crate::decl::*;
5use crate::kernel::ffi;
6
7#[derive(Default, Clone)]
18pub struct WString {
19 buf: Buffer,
20}
21
22impl std::fmt::Display for WString {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 let txt = match self.buf.to_string_checked() {
25 Ok(t) => t,
26 Err(e) => format!("PARSING ERROR: {}", e.to_string()),
27 };
28 std::fmt::Display::fmt(&txt, f)
29 }
30}
31impl std::fmt::Debug for WString {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 std::fmt::Debug::fmt(&self.buf, f)
34 }
35}
36
37impl std::cmp::PartialEq for WString {
38 fn eq(&self, other: &Self) -> bool {
39 self.cmp(other) == Ordering::Equal
40 }
41}
42impl std::cmp::Eq for WString {}
43
44impl std::cmp::PartialOrd for WString {
45 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
46 let ord = unsafe { ffi::lstrcmpW(self.as_ptr(), other.as_ptr()) };
47 Some(if ord < 0 {
48 Ordering::Less
49 } else if ord > 0 {
50 Ordering::Greater
51 } else {
52 Ordering::Equal
53 })
54 }
55}
56impl std::cmp::Ord for WString {
57 fn cmp(&self, other: &Self) -> Ordering {
58 self.partial_cmp(other).unwrap()
59 }
60}
61
62impl WString {
63 pub const SSO_LEN: usize = Buffer::SSO_LEN;
66
67 #[must_use]
71 pub fn from_opt_str(s: Option<impl AsRef<str>>) -> Self {
72 Self { buf: Buffer::from_opt_str(s) }
73 }
74
75 #[must_use]
79 pub fn from_str(s: impl AsRef<str>) -> Self {
80 Self { buf: Buffer::from_str(s, ForceHeap::No) }
81 }
82
83 #[must_use]
90 pub fn from_str_force_heap(s: impl AsRef<str>) -> Self {
91 Self { buf: Buffer::from_str(s, ForceHeap::Yes) }
92 }
93
94 #[must_use]
103 pub fn from_str_vec(v: &[impl AsRef<str>]) -> Self {
104 Self { buf: Buffer::from_str_vec(v) }
105 }
106
107 #[must_use]
112 pub fn from_wchars_count(src: *const u16, num_chars: usize) -> Self {
113 Self {
114 buf: Buffer::from_wchars_count(src, num_chars),
115 }
116 }
117
118 #[must_use]
127 pub unsafe fn from_wchars_nullt(src: *const u16) -> Self {
128 Self {
129 buf: unsafe { Buffer::from_wchars_nullt(src) },
130 }
131 }
132
133 #[must_use]
137 pub fn from_wchars_slice(src: &[u16]) -> Self {
138 Self { buf: Buffer::from_wchars_slice(src) }
139 }
140
141 #[must_use]
143 pub const fn new() -> Self {
144 Self { buf: Buffer::new() }
145 }
146
147 #[must_use]
150 pub fn new_alloc_buf(sz: usize) -> Self {
151 Self {
152 buf: Buffer::new_alloc_buf(sz, ForceHeap::No),
153 }
154 }
155
156 #[must_use]
169 pub const unsafe fn as_mut_ptr(&mut self) -> *mut u16 {
170 unsafe { self.buf.as_mut_ptr() }
171 }
172
173 #[must_use]
175 pub const fn as_mut_slice(&mut self) -> &mut [u16] {
176 self.buf.as_mut_slice()
177 }
178
179 #[must_use]
186 pub const fn as_ptr(&self) -> *const u16 {
187 self.buf.as_ptr()
188 }
189
190 #[must_use]
192 pub const fn as_slice(&self) -> &[u16] {
193 self.buf.as_slice()
194 }
195
196 #[must_use]
201 pub const fn buf_len(&self) -> usize {
202 self.buf.buf_len()
203 }
204
205 pub fn copy_to_slice(&self, dest: &mut [u16]) {
212 if !dest.is_empty() {
213 let usable_len = dest.len() - 1; self.as_slice()
215 .iter()
216 .zip(dest[..usable_len].iter_mut())
217 .for_each(|(src, dest)| *dest = *src);
218 dest[usable_len..]
219 .iter_mut()
220 .for_each(|dest| *dest = 0x0000); }
222 }
223
224 pub fn fill_with_zero(&mut self) {
226 self.as_mut_slice().iter_mut().for_each(|ch| *ch = 0x0000);
227 }
228
229 #[must_use]
231 pub const fn is_allocated(&self) -> bool {
232 self.buf.is_allocated()
233 }
234
235 #[must_use]
243 pub fn to_string_checked(&self) -> Result<String, std::string::FromUtf16Error> {
244 self.buf.to_string_checked()
245 }
246
247 #[must_use]
253 pub fn str_len(&self) -> usize {
254 unsafe { ffi::lstrlenW(self.buf.as_ptr()) as _ }
255 }
256
257 pub fn make_lowercase(&mut self) {
260 unsafe { ffi::CharLowerW(self.as_mut_ptr()) };
261 }
262
263 pub fn make_uppercase(&mut self) {
266 unsafe { ffi::CharUpperW(self.as_mut_ptr()) };
267 }
268
269 #[must_use]
295 pub fn parse(data: &[u8]) -> SysResult<Self> {
296 let mut data = data;
297 if data.is_empty() {
298 return Ok(Self::new()); }
300
301 let (encoding, sz_bom) = Encoding::guess(data);
302 data = &data[sz_bom..]; Ok(Self::from_wchars_slice(&match encoding {
305 Encoding::Ansi => Self::parse_ansi(data),
306 Encoding::Win1252 => MultiByteToWideChar(co::CP::WINDOWS_1252, co::MBC::NoValue, data)?,
307 Encoding::Utf8 => MultiByteToWideChar(co::CP::UTF8, co::MBC::NoValue, data)?,
308 Encoding::Utf16be => Self::parse_utf16(data, true),
309 Encoding::Utf16le => Self::parse_utf16(data, false),
310 Encoding::Utf32be
311 | Encoding::Utf32le
312 | Encoding::Scsu
313 | Encoding::Bocu1
314 | Encoding::Unknown => panic!("Encoding {} not implemented.", encoding),
315 }))
316 }
317
318 fn parse_ansi(data: &[u8]) -> Vec<u16> {
319 data.iter()
320 .take_while(|ch| **ch != 0x0000) .map(|ch| *ch as u16) .collect()
323 }
324
325 fn parse_utf16(data: &[u8], is_big_endian: bool) -> Vec<u16> {
326 let data = if data.len() % 2 == 1 {
327 &data[..data.len() - 1] } else {
329 data
330 };
331
332 data.chunks(2)
333 .take_while(|ch2| **ch2 != [0x00, 0x00]) .map(|ch2| {
335 if is_big_endian {
336 u16::from_be_bytes(ch2.try_into().unwrap())
337 } else {
338 u16::from_le_bytes(ch2.try_into().unwrap())
339 }
340 })
341 .collect()
342 }
343}
344
345#[derive(PartialEq, Eq)]
346enum ForceHeap {
347 Yes,
348 No,
349}
350
351enum Buffer {
352 Stack([u16; Self::SSO_LEN]),
353 Heap(Vec<u16>),
354 Unallocated,
355}
356
357impl Default for Buffer {
358 fn default() -> Self {
359 Self::Unallocated
360 }
361}
362
363impl Clone for Buffer {
364 fn clone(&self) -> Self {
365 match self {
366 Self::Unallocated => Self::Unallocated,
367 _ => {
368 let mut new_self = Self::new_alloc_buf(self.buf_len(), ForceHeap::No);
369 self.as_slice()
370 .iter()
371 .zip(new_self.as_mut_slice())
372 .for_each(|(src, dest)| *dest = *src);
373 new_self
374 },
375 }
376 }
377}
378
379impl std::fmt::Debug for Buffer {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381 let txt = match self.to_string_checked() {
382 Ok(t) => t,
383 Err(e) => format!("PARSING ERROR: {}", e.to_string()),
384 };
385 write!(
386 f,
387 "{}",
388 match self {
389 Self::Stack(_) => format!("STACK({}) \"{}\"", self.buf_len(), txt),
390 Self::Heap(_) => format!("HEAP({}) \"{}\"", self.buf_len(), txt),
391 Self::Unallocated => "UNALLOCATED \"\"".to_owned(),
392 }
393 )
394 }
395}
396
397impl Buffer {
398 pub const SSO_LEN: usize = 20;
399
400 #[must_use]
401 fn from_opt_str(s: Option<impl AsRef<str>>) -> Self {
402 match s {
403 Some(s) => Self::from_str(s, ForceHeap::No),
404 None => Self::Unallocated,
405 }
406 }
407
408 #[must_use]
409 fn from_str(s: impl AsRef<str>, force_heap: ForceHeap) -> Self {
410 let s_len = s.as_ref().encode_utf16().count();
411 if s_len == 0 {
412 Self::Unallocated
413 } else {
414 let num_chars = s_len + 1; let mut new_self = Self::new_alloc_buf(num_chars, force_heap);
416 s.as_ref()
417 .encode_utf16()
418 .zip(new_self.as_mut_slice())
419 .for_each(|(src, dest)| *dest = src);
420 new_self
421 }
422 }
423
424 #[must_use]
425 fn from_str_vec(v: &[impl AsRef<str>]) -> Self {
426 if v.is_empty() {
427 return Self::Unallocated; }
429
430 let tot_chars = v.iter() .fold(0, |tot, s| tot + s.as_ref().chars().count() + 1) + 1; let mut new_self = Self::new_alloc_buf(tot_chars, ForceHeap::No);
434 v.iter()
435 .map(|s| {
436 s.as_ref().encode_utf16().chain(std::iter::once(0x0000)) })
438 .flatten()
439 .zip(new_self.as_mut_slice())
440 .for_each(|(src, dest)| *dest = src);
441 new_self
442 }
443
444 #[must_use]
445 fn from_wchars_count(src: *const u16, num_chars: usize) -> Self {
446 if src.is_null() || num_chars == 0 {
447 Self::Unallocated
448 } else {
449 Self::from_wchars_slice(unsafe { std::slice::from_raw_parts(src, num_chars) })
450 }
451 }
452
453 #[must_use]
454 unsafe fn from_wchars_nullt(src: *const u16) -> Self {
455 Self::from_wchars_count(src, unsafe { ffi::lstrlenW(src) as _ })
456 }
457
458 #[must_use]
459 fn from_wchars_slice(src: &[u16]) -> Self {
460 if src.is_empty() {
461 Self::Unallocated
462 } else {
463 let num_chars = src
464 .iter()
465 .take_while(|ch| **ch != 0x0000) .count() + 1; let mut new_self = Self::new_alloc_buf(num_chars, ForceHeap::No);
468 src.iter()
469 .take_while(|ch| **ch != 0x0000) .zip(new_self.as_mut_slice())
471 .for_each(|(src, dest)| *dest = *src);
472 new_self
473 }
474 }
475
476 #[must_use]
477 const fn new() -> Self {
478 Self::Unallocated
479 }
480
481 #[must_use]
482 fn new_alloc_buf(num_chars: usize, force_heap: ForceHeap) -> Self {
483 if num_chars == 0 {
484 Self::Unallocated
485 } else if force_heap == ForceHeap::Yes || num_chars > Self::SSO_LEN {
486 Self::Heap(vec![0x0000; num_chars])
487 } else {
488 Self::Stack([0x0000; Self::SSO_LEN])
489 }
490 }
491
492 #[must_use]
493 const unsafe fn as_mut_ptr(&mut self) -> *mut u16 {
494 match self {
495 Self::Stack(arr) => arr.as_mut_ptr(),
496 Self::Heap(vec) => {
497 if vec.is_empty() {
498 std::ptr::null_mut() } else {
500 vec.as_mut_ptr()
501 }
502 },
503 Self::Unallocated => panic!("Trying to use an unallocated WString buffer."),
504 }
505 }
506
507 #[must_use]
508 const fn as_mut_slice(&mut self) -> &mut [u16] {
509 match self {
510 Self::Stack(arr) => arr,
511 Self::Heap(vec) => vec.as_mut_slice(),
512 Self::Unallocated => &mut [],
513 }
514 }
515
516 #[must_use]
517 const fn as_ptr(&self) -> *const u16 {
518 match self {
519 Self::Stack(arr) => arr.as_ptr(),
520 Self::Heap(vec) => {
521 if vec.is_empty() {
522 std::ptr::null() } else {
524 vec.as_ptr()
525 }
526 },
527 Self::Unallocated => std::ptr::null(),
528 }
529 }
530
531 #[must_use]
532 const fn as_slice(&self) -> &[u16] {
533 match self {
534 Self::Stack(arr) => arr,
535 Self::Heap(vec) => vec.as_slice(),
536 Self::Unallocated => &[],
537 }
538 }
539
540 #[must_use]
541 const fn buf_len(&self) -> usize {
542 match self {
543 Self::Stack(arr) => arr.len(),
544 Self::Heap(vec) => vec.len(),
545 Self::Unallocated => 0,
546 }
547 }
548
549 #[must_use]
550 const fn is_allocated(&self) -> bool {
551 match self {
552 Self::Unallocated => false,
553 _ => true,
554 }
555 }
556
557 #[must_use]
558 fn to_string_checked(&self) -> Result<String, std::string::FromUtf16Error> {
559 match self {
560 Self::Unallocated => Ok(String::new()),
561 _ => String::from_utf16(
562 &self
563 .as_slice()
564 .into_iter()
565 .take_while(|ch| **ch != 0x0000) .map(|ch| *ch)
567 .collect::<Vec<_>>(),
568 ),
569 }
570 }
571}